`timescale 1ns / 1ps

// N in --> 1 out
module reduce2
#(
    parameter N     = 3,
    parameter WIDTH = 8
)
(
    input   clk,
    input   rst,
    
    input   i_vld,
    output  i_rdy,
    input   [N*WIDTH-1 : 0] i_data,
    
    output  o_vld,
    input   o_rdy,
    output  [WIDTH-1: 0]    o_data
);

reg  [N*WIDTH-1 : 0] r_data;
reg                  r_vld;
wire                 r_rdy;

wire [$clog2(N)-1 : 0] cnt_out;
wire                   cnt_ena;
wire                   cnt_last;

wire [WIDTH-1 : 0] w_data [N-1 : 0];

assign i_rdy = r_rdy;
assign o_vld = r_vld;
assign o_data = w_data[cnt_out];

assign r_rdy = ~r_vld | (o_rdy & cnt_last);
assign cnt_ena = r_vld & o_rdy;

always @(posedge clk)
begin
    if (rst) begin
        r_vld <= 1'b0;
    end
    else begin
        if (r_rdy)
            r_vld  <= i_vld;
        if (r_rdy & i_vld)
            r_data <= i_data;
    end
end

zq_counter #(
    .N  (N)
) inst_cnt
(
    .clk    (clk),
    .rst    (rst),
    .clken  (cnt_ena),
    .last   (cnt_last),
    .out    (cnt_out)
);

genvar i;
generate
    for (i = 0; i < N; i = i + 1)
    begin
        assign w_data[i] = r_data[WIDTH * i + WIDTH - 1 : WIDTH * i]; 
    end
endgenerate

endmodule
